workflow.js ➔ create_dialog   F
last analyzed

Complexity

Conditions 20

Size

Total Lines 138
Code Lines 98

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 98
c 0
b 0
f 0
dl 0
loc 138
rs 0
cc 20

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like workflow.js ➔ create_dialog often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
$(document).ready(function() {
2
    $('body').on('click', '[data-dialog="delete"]', function(event) {
3
        event.preventDefault();
4
        var button = $(this),
5
            dialog = $('<div class="midcom-delete-dialog">'),
6
            spinner = $('<div class="spinner">' + get_spinner_template() + '</div>'),
7
            text = this.dataset.dialogText,
8
            relocate = $(this).data('relocate'),
9
            action = this.getAttribute('href') || this.dataset.action,
10
            options = {
11
                title:  this.dataset.dialogHeading,
12
                dialogClass: 'midcom-workflow-dialog midcom-workflow-dialog-delete',
13
                modal: true,
14
                width: 'auto',
15
                maxHeight: $(window).height(),
16
                buttons: [{
17
                    text: button.text().trim() || this.dataset.dialogHeading,
18
                    click: function() {
19
                        if (relocate) {
20
                            $('<form action="' + action + '" method="post" class="midcom-dialog-delete-form">')
21
                                .append($('<input type="submit" name="' + button.data('form-id') + '">'))
22
                                .append($('<input type="hidden" name="referrer" value="' + location.pathname + '">'))
23
                                .hide()
24
                                .prependTo('body');
25
                            $('input[name="' + button.data('form-id') + '"]').click();
26
                        } else {
27
                            var params = {
28
                                referrer: location.pathname
29
                            };
30
                            params[button.data('form-id')] = 1;
31
32
                            $.post(action, params).done(function(message) {
33
                                button.trigger('dialogdeleted', [message]);
34
                                dialog.dialog("close");
35
                                if (   typeof window.parent.$ !== "undefined"
36
                                    && window.parent.$('#midcom-dialog').length > 0 ) {
37
                                    window.parent.$('#midcom-dialog')
38
                                        .dialog('close')
39
                                        .trigger('dialogdeleted', [message]);
40
                                }
41
                            });
42
                        }
43
                    }
44
                }, {
45
                    text: this.dataset.dialogCancelLabel,
46
                    click: function() {
47
                        $(this).dialog("close");
48
                    }
49
                }]
50
            };
51
52
        if ($('.midcom-delete-dialog').length > 0) {
53
            $('.midcom-delete-dialog').remove();
54
        }
55
56
        if (this.dataset.recursive === 'true') {
57
            dialog.addClass('loading');
58
            options.buttons[0].disabled = true;
59
            $.getJSON(MIDCOM_PAGE_PREFIX + 'midcom-exec-midcom.helper.reflector/list-children.php',
60
                {guid: this.dataset.guid},
61
                function (data) {
62
                    function render(carry, item) {
63
                        carry += '<li class="leaf ' + item['class'] + '">' + item.icon + ' ' + item.title;
64
                        if (item.children) {
65
                            carry += item.children.reduce(render, '<ul class="folder_list">') + '</ul>';
66
                        }
67
                        return carry + '</li>';
68
                    }
69
70
                    if (data.length > 0) {
71
                        $('<ul class="folder_list">')
72
                            .append($(data.reduce(render, '')))
73
                            .appendTo($('#delete-child-list'));
74
                    } else {
75
                        dialog.find('p.warning').hide();
76
                    }
77
                    options.buttons[0].disabled = false;
78
79
                    dialog
80
                        .removeClass('loading')
81
                        .dialog('option', 'position', dialog.dialog('option', 'position'))
82
                        .dialog('option', 'buttons', options.buttons)
83
                        .focus();
84
                });
85
        } else {
86
            text = '<p>' + text + '</p>';
87
        }
88
89
        dialog
90
            .css('min-width', '300px') // This should be handled by dialog's minWidth option, but that doesn't work with width: "auto"
91
                                       // Should be fixed in https://github.com/jquery/jquery-ui/commit/643b80c6070e2eba700a09a5b7b9717ea7551005
92
            .append($(text))
93
            .append(spinner)
94
            .appendTo($('body'));
95
96
        make_dialog(dialog, options);
97
        dialog.on( "dialogclose", function() {
98
            button.parent()
99
                .find('.ui-state-disabled')
100
                .removeClass('ui-state-disabled');
101
        });
102
    });
103
104
    $('body').on('click', '[data-dialog="dialog"]', function(event) {
105
        event.preventDefault();
106
        let url, 
107
            href = this.getAttribute('href');
108
109
        if (this.classList.contains('dialog-extra-button')) {
110
            href = this.dataset.action;
111
        }
112
113
        if ($('.midcom-workflow-dialog').is(':visible') && $('.midcom-workflow-dialog iframe').length > 0) {
114
            url = $('.midcom-workflow-dialog iframe')[0].contentWindow.location.href;
115
        }
116
        if (url != href) {
0 ignored issues
show
Bug introduced by
The variable url does not seem to be initialized in case $(".midcom-workflow-dial...log iframe").length > 0 on line 113 is false. Are you sure this can never be the case?
Loading history...
117
            create_dialog($(this), $(this).find('.toolbar_label').text() || this.title, href);
118
        }
119
    });
120
121
    $('body').on('click', '[data-dialog="confirm"]', function(event) {
122
        event.preventDefault();
123
        var button = $(this),
124
            dialog = $('<div class="midcom-confirm-dialog">'),
125
            options = {
126
                title:  this.dataset.dialogHeading,
127
                modal: true,
128
                width: 'auto',
129
                maxHeight: $(window).height(),
130
                buttons: [{
131
                    text: this.dataset.dialogConfirmLabel,
132
                    click: function() {
133
                        button.closest('form').submit();
134
                    }
135
                }, {
136
                    text: this.dataset.dialogCancelLabel,
137
                    click: function() {
138
                        $(this).dialog("close");
139
                    }
140
                }]
141
            };
142
143
        if ($('.midcom-confirm-dialog').length > 0) {
144
            $('.midcom-confirm-dialog').remove();
145
        }
146
147
        dialog
148
            .css('min-width', '300px') // This should be handled by dialog's minWidth option, but that doesn't work with width: "auto"
149
                                       // Should be fixed in https://github.com/jquery/jquery-ui/commit/643b80c6070e2eba700a09a5b7b9717ea7551005
150
            .append($('<p>' + this.dataset.dialogText + '</p>'))
151
            .appendTo($('body'));
152
        make_dialog(dialog, options);
153
    });
154
    $('body').on('click', '.midcom-workflow-dialog .ui-dialog-buttonpane .ui-button', function() {
155
        var pane = $(this).closest('.ui-dialog-buttonpane'),
156
            iframe = pane.prevAll('#midcom-dialog').find('iframe'),
157
            disabler = function() {
158
                pane.find('.ui-button')
159
                    .addClass('ui-state-disabled');
160
            };
161
162
        if (!$(this).hasClass('dialog-extra-button') && $('form.datamanager2', iframe.contents()).length > 0) {
163
            $('form.datamanager2', iframe.contents()).on('submit', disabler);
164
        } else {
165
            disabler();
166
        }
167
    });
168
});
169
170
function get_spinner_template() {
171
    return typeof WORKFLOW_SPINNER_TEMPLATE != 'undefined' ? WORKFLOW_SPINNER_TEMPLATE : '<i class="fa fa-pulse fa-spinner"></i>';
172
}
173
174
function create_dialog(control, title, url) {
175
    if ($('.midcom-workflow-dialog').is(':visible')) {
176
        $('body').addClass('midcom-workflow-switching');
177
        $('.midcom-workflow-dialog .ui-dialog-content').dialog('close');
178
    }
179
180
    var dialog, iframe, spinner, is_scrolling,
181
        config = {
182
            dialogClass: 'midcom-workflow-dialog',
183
            buttons: [],
184
            title: title,
185
            height:  590,
186
            width: 800,
187
            close: function() {
188
                control.removeClass('active');
189
                iframe.css('visibility', 'hidden');
190
                // second clause is an IE11 workaround
191
                if (iframe[0].contentWindow && iframe[0].contentWindow.hasOwnProperty('stop')) {
192
                    iframe[0].contentWindow.stop();
193
                }
194
                if ($('body').hasClass('midcom-workflow-switching')) {
195
                    $('body').removeClass('midcom-workflow-switching');
196
                } else {
197
                    $('body').removeClass('midcom-workflow-active');
198
                }
199
            },
200
            open: function() {
201
                dialog.closest('.ui-dialog').focus();
202
                $('body').addClass('midcom-workflow-active');
203
            }};
204
205
    if (control.data('dialog-cancel-label')) {
206
        config.buttons.push({
207
            text: control.data('dialog-cancel-label'),
208
            click: function() {
209
                $(this).dialog( "close" );
210
            }
211
        });
212
    }
213
214
    // Workaround for jqueryui incompatibility between position widget & css fixed position
215
    function keep_dialog_fixed () {
216
        var ui_dialog = dialog.closest('.ui-dialog'),
217
            viewport_position = ui_dialog[0].getBoundingClientRect();
218
219
        window.clearTimeout(is_scrolling);
220
221
        ui_dialog.css({
222
            position: 'fixed',
223
            top: viewport_position.top + 'px',
224
            left: viewport_position.left + 'px'
225
        });
226
227
        is_scrolling = setTimeout(function() {
228
            ui_dialog.css({
229
                position: 'absolute',
230
                top: ui_dialog.offset().top + 'px',
231
                left: ui_dialog.offset().left + 'px'
232
            });
233
        }, 500);
234
    }
235
236
    if ($('#midcom-dialog').length > 0) {
237
        dialog = $('#midcom-dialog');
238
        iframe = dialog.find('> iframe');
239
        spinner = dialog.find('> .spinner').show();
240
        config.height = dialog.dialog('option', 'height');
241
        config.width = dialog.dialog('option', 'width');
242
        if (   config.width > window.innerWidth
243
            || config.height > window.innerHeight) {
244
            config.position = { my: "center", at: "center", of: window, collision: 'flipfit' };
245
        }
246
    } else {
247
        spinner = $('<span class="spinner">' + get_spinner_template() + '</span>');
248
        iframe = $('<iframe name="datamanager-dialog"'
249
                   + ' frameborder="0"'
250
                   + ' width="100%"'
251
                   + ' height="100%"'
252
                   + ' scrolling="auto"></iframe>')
253
           .on('load', function() {
254
               // this is only here as fallback in case dialog.js doesn't run for whatever reason
255
               spinner.hide();
256
               this.style.visibility = 'visible';
257
           });
258
259
        dialog = $('<div id="midcom-dialog" class="has-iframe"></div>')
260
            .append(spinner)
261
            .append(iframe)
262
            .on('dialogcreate', function() {
263
                var maximized = false,
264
                    saved_options = {};
265
                $(this).prevAll('.ui-dialog-titlebar').on('dblclick', function() {
266
                    if (!maximized) {
267
                        saved_options.position = dialog.dialog('option', 'position');
268
                        saved_options.width = dialog.dialog('option', 'width');
269
                        saved_options.height = dialog.dialog('option', 'height');
270
                        dialog.dialog('option', {
271
                            width: '99%',
272
                            height: $(window).height(),
273
                            position: {my: 'center top', at: 'center top', of: window}
274
                        });
275
                        maximized = true;
276
                    } else {
277
                        dialog.dialog('option', {
278
                            height: saved_options.height,
279
                            width: saved_options.width,
280
                            position: saved_options.position
281
                        });
282
                        maximized = false;
283
                    }
284
                });
285
            })
286
            .on('dialogopen', function() {
287
                window.addEventListener('scroll', keep_dialog_fixed, false);
288
            })
289
            .on('dialogclose', function() {
290
                window.removeEventListener('scroll', keep_dialog_fixed, false);
291
            })
292
            .appendTo($('body'));
293
    }
294
295
    config.height = Math.min(config.height, window.innerHeight);
296
    config.width = Math.min(config.width, window.innerHeight);
297
298
    if (url) {
299
        iframe.attr('src', url);
300
    }
301
302
    control.addClass('active');
303
    if (   control.parent().attr('role') === 'gridcell'
304
        && control.closest('.jqgrow').hasClass('ui-state-highlight') === false) {
305
        //todo: find out why the click doesn't bubble automatically
306
        control.parent().trigger('click');
307
    }
308
309
    make_dialog(dialog, config);
310
    dialog.dialog("instance").uiDialog.draggable("option", "containment", false);
311
}
312
313
function make_dialog(node, config) {
314
315
    if (!config.hasOwnProperty('buttons')) {
316
        config.buttons = [];
317
    }
318
    if (config.buttons.length === 0) {
319
        // This is not ideal, but otherwise buttons added by dialog.js are not rendered
320
        config.buttons.push({
321
            text: '...',
322
            click: function() {},
323
            css: {visibility: 'hidden'}
324
        });
325
    }
326
327
    var backup = false;
328
329
    if (typeof($.fn.popover) != 'undefined') {
330
        backup = $.button;
331
        $.widget.bridge("button", $.ui.button);
332
    }
333
334
    node
335
        .on('dialogopen', function() {
336
            // workaround for jqueryui rendering issue
337
            node.prev().find('.ui-dialog-titlebar-close').css('outline', 'none');
338
        })
339
        .dialog(config);
340
341
    if (backup) {
342
        $.button = backup;
343
    }
344
}
345